#ifndef XDG_TCP_CLIENT_HPP
#define XDG_TCP_CLIENT_HPP

#include <QObject>
#include <QTcpSocket>
#include <QMutex>
#include <QByteArray>
#include <QAbstractSocket>
#include <QThread> // 用于断言

// 前向声明
class QEventLoop;

/**
 * @class xdgTcpClient
 * @brief 一个真正线程安全的、基于Qt的TCP客户端类 (使用小端字节序)。
 *
 * 该类封装了QTcpSocket，并自动处理 "4字节头部 + 消息体" 的粘包和拆包。
 *
 * @section thread_safety 线程安全
 * 所有的公共API (connectToServer, disconnectFromServer, sendMessage,
 * isConnected, sendAndReceive) 都可以从**任何**线程安全地调用，
 * 无论 xdgTcpClient 实例本身位于哪个线程。
 *
 * 它通过 QMetaObject::invokeMethod 将跨线程的调用排队到 xdgTcpClient
 * 实例所在的线程事件循环中去执行，从而保证了 Qt 对象的线程亲和性。
 *
 * @section usage 使用示例
 * @code
 * // 示例 1: 在主线程中使用
 * xdgTcpClient* client = new xdgTcpClient(this);
 * connect(client, &xdgTcpClient::messageReceived, this, &MyClass::onMessage);
 * client->connectToServer("127.0.0.1", 12345);
 * // 此时，你可以从任何其他工作线程安全地调用 client->sendMessage(...)
 *
 * // 示例 2: 移动到专用IO线程 (推荐用于高性能网络)
 * QThread* ioThread = new QThread(this);
 * xdgTcpClient* client = new xdgTcpClient(); // 1. 无父对象创建
 * client->moveToThread(ioThread);      // 2. 移动到线程
 *
 * // 3. 连接信号
 * connect(client, &xdgTcpClient::messageReceived, this, &MyClass::onMessage);
 * connect(ioThread, &QThread::finished, client, &QObject::deleteLater);
 *
 * ioThread->start(); // 4. 启动线程
 *
 * // 5. 现在可以从主线程或任何其他线程安全地调用
 * client->connectToServer("127.0.0.1", 12345);
 *
 * // 6. 同步调用 (必须在 *非* GUI 和 *非* IO 线程中！)
 * QtConcurrent::run([=](){
 * QByteArray response = client->sendAndReceive("GetInfo");
 * });
 * @endcode
 */
class xdgTcpClient : public QObject
{
    Q_OBJECT

public:
    /**
     * @brief 构造函数。
     * @param parent 父QObject对象。
     */
    explicit xdgTcpClient(QObject *parent = nullptr);

    /**
     * @brief 析构函数。
     */
    ~xdgTcpClient();

    /**
     * @brief 检查当前是否已连接。
     * @return 如果套接字当前处于 ConnectedState 状态，则返回true。
     * @note 该函数是线程安全的 (使用 BlockingQueuedConnection)。
     */
    bool isConnected() const;

    /**
     * @brief 获取底层的 socket 指针。
     * @warning
     * 1. 只有在 xdgTcpClient 自己的线程中才能安全调用此函数！
     * 2. 主要用于调试或获取错误字符串，严禁跨线程调用。
     * @return 指向内部QTcpSocket实例的指针。
     */
    QTcpSocket* socket() const
    {
        Q_ASSERT_X(QThread::currentThread() == this->thread(),
                   "xdgTcpClient::socket()",
                   "socket() must be called from the client's own thread.");
        return m_socket;
    }

    // --- 线程安全的公共 API (可从任意线程调用) ---
public:
    /**
     * @brief [线程安全] 异步连接到服务器。
     * @param host 服务器主机名或IP地址。
     * @param port 服务器端口号。
     * @note 此调用会立即返回，连接请求会被排队到客户端线程中执行。
     */
    void connectToServer(const QString& host, quint16 port);

    /**
     * @brief [线程安全] 从服务器断开连接。
     * @note 此调用会立即返回，断开请求会被排队到客户端线程中执行。
     */
    void disconnectFromServer();

    /**
     * @brief [线程安全] [异步] 发送消息。
     * 函数会将消息打包成 "4字节小端长度头 + 消息体" 的格式，然后进行发送。
     * @param message 要发送的消息体。
     * @note API变更：此函数现在返回 void (因为它是异步排队的)。
     */
    void sendMessage(const QByteArray& message);

    /**
     * @brief [线程安全] [阻塞] 发送一个请求并等待一个响应。
     *
     * 该函数会发送 `request` 数据包，然后阻塞**调用者**线程，直到收到服务器的
     * 第一个数据包或超时。
     *
     * @warning **绝对不要在主 GUI 线程或 xdgTcpClient 自己的线程中调用此函数！**
     * 请在独立的工作线程 (如 QThread, QtConcurrent::run) 中使用它。
     *
     * @param request 要发送的请求数据。
     * @param timeoutMsecs 等待响应的超时时间（毫秒）。
     * @return 服务器返回的响应数据。如果超时、连接断开或发生错误，则返回一个空的 QByteArray。
     * @note 此函数是线程安全的，但整个客户端实例在同一时间只允许一个阻塞调用。
     */
    QByteArray sendAndReceive(const QByteArray& request, int timeoutMsecs = 5000);


    // --- 信号 (从客户端线程发出) ---
signals:
    void connected();
    void disconnected();
    void messageReceived(const QByteArray& message);
    void errorOccurred(QAbstractSocket::SocketError socketError);

    // --- 内部槽 (在客户端线程中运行) ---
private slots:
    // 实际的 Socket 信号处理
    void onConnected();
    void onDisconnected();
    void onReadyRead();
    void onErrorOccurred(QAbstractSocket::SocketError socketError);

    // 内部工作槽 (由公共API通过 invokeMethod 派发)
    // 必须是 public slots 才能被 invokeMethod(const char*) 调用
public slots:
    void _p_doConnect(const QString& host, quint16 port);
    void _p_doDisconnect();
    void _p_doSend(const QByteArray& message);
    QAbstractSocket::SocketState _p_getState() const;

private:
    xdgTcpClient(const xdgTcpClient&) = delete;
    xdgTcpClient& operator=(const xdgTcpClient&) = delete;

    // 在 onReadyRead 中被调用
    void processBuffer();

    QTcpSocket* m_socket;
    QByteArray m_buffer;
    qint32 m_expectedBodySize;

    // --- for blocking call ---
    // 确保 sendAndReceive 的互斥访问和状态传递
    mutable QMutex m_blockingMutex;
    QByteArray m_blockingResponse;
    bool m_isBlockingCallActive; // 标记 processBuffer 应该捕获下一条消息
    QEventLoop* m_blockingLoop;  // 指向 sendAndReceive 栈上的 QEventLoop
};

#endif // XDG_TCP_CLIENT_HPP
